﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PlanningGIS.ArcGIS.Custom;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Geodatabase;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.Carto;
using PlanningGIS.Util;
using PlanningGIS.Util.Regular;
using PlanningGIS.ArcGIS;

namespace PlanningGIS.MapSheet
{
    /// <summary>
    /// 左下角点图幅标准
    /// </summary>
    public class LowerLeftMapsheet : BaseMapsheet, IMapsheet
    {
        /// <summary>
        /// 构造函数
        /// </summary>
        public LowerLeftMapsheet()
            : base()
        {
            
        }

        #region 创建图幅层
        /// <summary>
        /// 根据空间对象创建图幅图层
        /// </summary>
        /// <param name="geometry">要创建图幅的空间范围：矩形或多边形</param>
        /// <param name="sheetFeatureClass">要创建到的图幅图层</param>
        /// <param name="fieldSheetName">图幅名称字段</param>
        /// <param name="scale">要创建图幅的比例尺</param>
        /// <param name="removespace">是否移除与空间对象不想交的空白图幅。默认为false：不移除</param>
        /// <returns>true创建成功；false创建失败</returns>
        public bool CreateMapSheet(IGeometry geometry, IFeatureClass sheetFeatureClass, string fieldSheetName, SheetScale scale, bool removespace = false)
        {
            if (geometry == null)
                throw new Exception("要创建图幅的空间对象不能为空");
            if (sheetFeatureClass == null)
                throw new Exception("所要创建的图幅图层不能为空");
            if (string.IsNullOrEmpty(fieldSheetName) || string.IsNullOrWhiteSpace(fieldSheetName))
                throw new Exception("图幅图层中图幅名称字段不能为空");
            int fIndex = sheetFeatureClass.FindField(fieldSheetName);
            if (fIndex == -1)
                throw new Exception("图幅图层中不存在名称为" + fieldSheetName + "的图幅名称字段！");
            if (scale == null)
                throw new Exception("要创建图幅的比例尺不能为空");            
            if (scale.Index < 0 )
                throw new Exception("不存在" + scale.Value.ToString() + "的常规比例尺，请改用常规的比例尺！"); 
            bool suc = false;
            base.RelationalFeatureClass = null;
            base.RelationalGeometry = geometry as IRelationalOperator;
            if ( string.IsNullOrEmpty(scale.Format) || string.IsNullOrWhiteSpace(scale.Format))
            {
                suc = base.CreateBaseSheet(geometry.Envelope, sheetFeatureClass, fIndex, scale, removespace);
            }
            else
            {
                suc = CreateMapSheet(geometry.Envelope, sheetFeatureClass, fIndex, scale, removespace);
            }
            base.RelationalGeometry = null;
            return suc;
        }

        /// <summary>
        /// 根据图层（如行政区化）创建图幅图层
        /// </summary>
        /// <param name="fullFeatureClass">要创建图幅的图层范围：如行政区化</param>
        /// <param name="sheetFeatureClass">要创建到的图幅图层</param>
        /// <param name="fieldSheetName">图幅名称字段</param>
        /// <param name="scale">要创建图幅的比例尺</param>
        /// <param name="removespace">是否移除与空间对象不想交的空白图幅。默认为false：不移除</param>
        /// <returns>true创建成功；false创建失败</returns>
        public bool CreateMapSheet(IFeatureClass fullFeatureClass, IFeatureClass sheetFeatureClass, string fieldSheetName, SheetScale scale, bool removespace = false)
        {
            if (fullFeatureClass == null) throw new Exception("要创建图幅的空间对象不能为空");
            if (scale == null) throw new Exception("要创建图幅的比例尺不能为空");
            if (sheetFeatureClass == null) throw new Exception("所要创建的图幅图层不能为空");
            if (scale.Index < 0) throw new Exception("不存在" + scale.Value.ToString() + "的常规比例尺，请改用常规的比例尺！");                
            if (string.IsNullOrEmpty(fieldSheetName) || string.IsNullOrWhiteSpace(fieldSheetName))
                throw new Exception("图幅图层中图幅名称字段不能为空");            
            int fIndex = sheetFeatureClass.FindField(fieldSheetName);
            if (fIndex == -1) throw new Exception("图幅图层中不存在名称为" + fieldSheetName + "的图幅名称字段！"); 
               
            bool suc = false;
            base.RelationalGeometry = null;
            base.RelationalFeatureClass = fullFeatureClass;
            IFeatureLayer lyr = new ESRI.ArcGIS.Carto.FeatureLayer();
            lyr.FeatureClass = fullFeatureClass;
            IEnvelope extent = lyr.AreaOfInterest;
            if (string.IsNullOrEmpty(scale.Format) || string.IsNullOrWhiteSpace(scale.Format))
                suc = base.CreateBaseSheet(extent, sheetFeatureClass, fIndex, scale, removespace);
            else
                suc = CreateMapSheet(extent, sheetFeatureClass, fIndex, scale, removespace);
            base.RelationalFeatureClass = null;
            Marshal.ReleaseComObject(lyr);
            lyr = null;
            return suc;
        }

        /// <summary>
        /// 根据空间对象创建图幅图层
        /// </summary>
        /// <param name="extent">要创建图幅的空间范围：矩形</param>
        /// <param name="sheetFeatureClass">要创建到的图幅图层</param>
        /// <param name="fIndex">图幅名称字段</param>
        /// <param name="scale">要创建图幅的比例尺</param>
        /// <param name="removespace">是否移除与空间对象不想交的空白图幅。默认为false：不移除</param>
        /// <returns>true创建成功；false创建失败</returns>
        private bool CreateMapSheet(IEnvelope extent, IFeatureClass sheetFeatureClass, int fIndex, SheetScale scale, bool removespace = false)
        {
            if (scale.ParentValue > 0)
            {
                SheetScale parent = SheetScale.Create(scale.ParentValue);
                if (parent.Index < 0)
                    throw new Exception("上一级比例尺的值" + scale.ParentValue.ToString() + "不是标准比例尺,请重新设置");
            }
            int[] idxes = GetIndexes(sheetFeatureClass);
            idxes[4] = fIndex;
            base.SetSize(scale);
            base.SetFullExtent(extent);
            if (_Progressor != null)
                _Progressor.SetMaxValue(ColCount * RowCount);
            object missing = Type.Missing;
            IRelationalOperator relOp = extent as IRelationalOperator;
            IFeatureCursor featCursor = sheetFeatureClass.Insert(true);
            int index = 0;
            double tmph = Height / RowLength;
            double tmpw = Width / ColLength;     
            for (double x = XMin; x < XMax; x+=Width)
            {
                for (double y = YMin; y < YMax; y+=Height)
                {
                    index++;
                    if (_Progressor != null) _Progressor.SetCurrentValue(index);                       
                    string mapno = GetFormatCode(x, y, scale.Format, scale.XOffset, scale.YOffset);
                    double temy = y;
                    for (int m = RowLength; m > 0; m--)
                    {
                        double tmpx = x;                        
                        for (int n = 1; n <= ColLength; n++)
                        {                  
                            string tmpno = GetSheetCode(mapno, n, m, ColLength, RowLength);
                            IPolygon polygon = GeometryHelper.ExtentToPolygon(tmpx, temy, tmpx + tmpw, temy + tmph);
                            tmpx += tmpw;
                            if (scale.ParentValue >0)
                                if (relOp.Disjoint(polygon))
                                    continue;
                            if (removespace)
                                if (Disjoint(polygon))
                                    continue;
                            IFeatureBuffer featureBuffer = sheetFeatureClass.CreateFeatureBuffer();
                            featureBuffer.Shape = polygon;
                            featureBuffer.set_Value(fIndex, tmpno);
                            if (idxes != null && idxes.Length > 0)
                            {
                                if (idxes[0] >= 0) featureBuffer.set_Value(idxes[0], _GetMapSheet(tmpx - 3 * tmpw / 2, temy + 3 * tmph / 2, scale).Code);
                                if (idxes[1] >= 0) featureBuffer.set_Value(idxes[1], _GetMapSheet(tmpx - tmpw / 2, temy + 3 * tmph / 2, scale).Code);
                                if (idxes[2] >= 0) featureBuffer.set_Value(idxes[2], _GetMapSheet(tmpx + tmpw / 2, temy + 3 * tmph / 2, scale).Code);
                                if (idxes[3] >= 0) featureBuffer.set_Value(idxes[3], _GetMapSheet(tmpx - 3 * tmpw / 2, temy + tmph / 2, scale).Code);
                                if (idxes[5] >= 0) featureBuffer.set_Value(idxes[5], _GetMapSheet(tmpx + tmpw / 2, temy + tmph / 2, scale).Code);
                                if (idxes[6] >= 0) featureBuffer.set_Value(idxes[6], _GetMapSheet(tmpx - 3 * tmpw / 2, temy - tmph / 2, scale).Code);
                                if (idxes[7] >= 0) featureBuffer.set_Value(idxes[7], _GetMapSheet(tmpx - tmpw / 2, temy - tmph / 2, scale).Code);
                                if (idxes[8] >= 0) featureBuffer.set_Value(idxes[8], _GetMapSheet(tmpx + tmpw / 2, temy - tmph / 2, scale).Code);
                            }
                            featCursor.InsertFeature(featureBuffer);
                        }
                        temy += tmph;
                    }
                    if (index % 1000 == 0)
                        featCursor.Flush();
                }
            }
            featCursor.Flush();
            Marshal.ReleaseComObject(featCursor);
            featCursor = null;
            if (_Progressor != null)
                _Progressor.Stop();
            return true;
        }
        #endregion

        /// <summary>
        /// 获取图幅图层中图幅周边八个图幅图号字段的索引号，
        /// 顺序与下面【根据图号获取周边图幅】的顺序保持一直
        /// </summary>
        /// <param name="featureClass"></param>
        /// <returns></returns>
        private int[] GetIndexes(IFeatureClass featureClass)
        {
            int[] idxes = new int[9];
            idxes[0] = featureClass.FindField(SheetHelper.F_LeftTop);
            idxes[1] = featureClass.FindField(SheetHelper.F_TopIn);
            idxes[2] = featureClass.FindField(SheetHelper.F_RightTop);
            idxes[3] = featureClass.FindField(SheetHelper.F_LeftIn);
            idxes[4] = 4;
            idxes[5] = featureClass.FindField(SheetHelper.F_RightIn);
            idxes[6] = featureClass.FindField(SheetHelper.F_LeftUnder);
            idxes[7] = featureClass.FindField(SheetHelper.F_UnderIn);            
            idxes[8] = featureClass.FindField(SheetHelper.F_RightUnder);            
            return idxes;
        }

        /// <summary>
        /// 根据图幅号获取图幅对象
        /// </summary>
        /// <param name="sheetcode">不带有比例尺标识的图幅号</param>
        /// <param name="scale">对应的比例尺</param>
        /// <returns></returns>
        public Mapsheet GetMapSheet(string sheetcode, SheetScale scale)
        {
            if (scale == null)
                throw new Exception("要创建图幅的比例尺不能为空");
            if (scale.Index < 0)
                throw new Exception("不存在" + scale.Value.ToString() + "的常规比例尺，请改用常规的比例尺！");
            if (IsGBCode(sheetcode))
            {
                return GetMapSheet(sheetcode);
            }  
            SetSize(scale);
            return MathMapSheet(sheetcode, scale);
        }

        /// <summary>
        /// 根据坐标点获取图幅对象
        /// </summary>
        /// <param name="x">指定的坐标点的X坐标（经度）</param>
        /// <param name="y">指定的坐标点的Y坐标（纬度）</param>
        /// <param name="scale">对应的比例尺</param>
        /// <returns></returns>
        public Mapsheet GetMapSheet(double x, double y, SheetScale scale)
        {
            if (scale == null)
                throw new Exception("要创建图幅的比例尺不能为空");
            if (scale.Index < 0)
                throw new Exception("不存在" + scale.Value.ToString() + "的常规比例尺，请改用常规的比例尺！");
            SetSize(scale);
            return _GetMapSheet(x, y, scale);
        }

        /// <summary>
        /// 根据坐标点获取图幅对象
        /// </summary>
        /// <param name="x">指定的坐标点的X坐标（经度）</param>
        /// <param name="y">指定的坐标点的Y坐标（纬度）</param>
        /// <param name="scale">对应的比例尺</param>
        /// <returns></returns>
        private Mapsheet _GetMapSheet(double x, double y, SheetScale scale)
        {
            if (string.IsNullOrEmpty(scale.Format) || string.IsNullOrWhiteSpace(scale.Format))
                return GetBaseSheet(x, y, scale);
            else
                return MathMapSheet(x, y, scale);
        }

        /// <summary>
        /// 获取坐标点在指定比例尺的图幅号
        /// </summary>
        /// <param name="x">指定的坐标点的X坐标（经度）</param>
        /// <param name="y">指定的坐标点的Y坐标（纬度）</param>
        /// <param name="scale">对应的比例尺</param>
        /// <returns></returns>
        public string GetSheetCode(double x, double y, SheetScale scale)
        {
            if (scale == null)
                throw new Exception("要创建图幅的比例尺不能为空");
            if (scale.Index < 0)
                throw new Exception("不存在" + scale.Value.ToString() + "的常规比例尺，请改用常规的比例尺！");            
            SetSize(scale);
            Mapsheet tf = null;
            if (string.IsNullOrEmpty(scale.Format) || string.IsNullOrWhiteSpace(scale.Format))
            {
                if (x > 180 || x < 0 || y > 90 || y < 0)
                    throw new Exception("坐标范围不在有效的范围内：X（0-180）、Y（0-90）");
                tf = GetBaseSheet(x, y, scale);
            }
            else
                tf = MathMapSheet(x, y, scale);
            return tf == null ? "" : tf.Code;
        }

        /// <summary>
        /// 根据图幅号获取西南角（左下角）点的坐标
        /// </summary>
        /// <param name="sheetcode">不带有比例尺标识的图幅号</param>
        /// <param name="scale">对应的比例尺</param>
        /// <returns></returns>
        public IPoint GetWestSouthPoint(string sheetcode, SheetScale scale)
        {
            if (IsGBCode(sheetcode))
            {
                return GetWestSouthPoint(sheetcode);
            }
            if (scale == null)
                throw new Exception("要创建图幅的比例尺不能为空");
            if (scale.Index < 0)
                throw new Exception("不存在" + scale.Value.ToString() + "的常规比例尺，请改用常规的比例尺！");
            
            SetSize(scale);
            Mapsheet tf = MathMapSheet(sheetcode, scale);;
            return tf == null ? null : tf.Geometry.Envelope.LowerLeft;
        }

        /// <summary>
        /// 根据图号创建图幅
        /// </summary>
        /// <param name="sheetcode"></param>
        /// <param name="scale"></param>
        /// <returns></returns>
        private Mapsheet MathMapSheet(string sheetcode, SheetScale scale)
        {
            double x = 0;
            double y = 0;
            if (!CheckFormatCode(sheetcode, scale.Format, out x, out y, scale.XOffset, scale.YOffset))
                return null;
            string DD = GetMatchString(scale.Format, "d");
            int ilen = 1;
            int jlen = 1;
            if (!string.IsNullOrEmpty(DD) && !string.IsNullOrWhiteSpace(DD))
            {
                if (scale.ParentValue < 10)
                    return null;
                SheetScale sp = SheetScale.Create(scale.ParentValue);
                if (sp.Index < 0)
                    return null;
                sp.XOffset = scale.XOffset;
                sp.YOffset = scale.YOffset;
                int index = scale.Format.IndexOf(DD);
                string s = sheetcode.Substring(index + (sheetcode.Length-scale.Format.Length), DD.Length);
                int n = 0;
                if (!int.TryParse(s, out n))
                    return null;
                ilen = scale.ParentValue / scale.Value;
                jlen = ilen;
                for (int i = 1; i <= ilen; i++)
                {
                    int m = 0;
                    for (int j = 1; j <= jlen; j++)
                    {
                        m = (j - 1) * ilen + i;
                        if (m == n)
                        {
                            x += (i - 1) * (Width / ilen);
                            y += (jlen - j) * (Height / jlen);
                            break;
                        }
                    }
                    if (m == n) break;
                }                
            }
            return new Mapsheet()
            {
                Code = sheetcode,
                Geometry = GeometryHelper.ExtentToPolygon(x, y, x + (Width / ilen), y + (Height / jlen))
            };
        }
       
        /// <summary>
        /// 根据坐标创建图幅，先要初始化图幅范围
        /// </summary>
        /// <param name="x">图幅中的点或左下角点的X坐标</param>
        /// <param name="y">图幅中的点或左下角点的Y坐标</param>
        /// <param name="scale"></param>
        /// <returns></returns>
        private Mapsheet MathMapSheet(double x, double y, SheetScale scale)
        {
            double xmax = base.GetCeiling(x, (int)Width);
            double ymax = base.GetCeiling(y, (int)Height);
            double xmin = base.GetFloor(x, (int)Width);
            double ymin = base.GetFloor(y, (int)Height);
            string mapno = GetFormatCode(xmin, ymin, scale.Format, scale.XOffset, scale.YOffset);
            if (scale.ParentValue > 0)
            {
                double coltem = (x - xmin) * 1.0 / (Width / ColLength);
                int colindex = (int)Math.Ceiling(coltem); //整除需要+1  
                if (coltem == colindex) colindex += 1;
                int rowindex = RowLength - (int)Math.Floor((y - ymin) / (Height / RowLength));
                mapno = GetSheetCode(mapno, colindex, rowindex, ColLength, RowLength);
                return new Mapsheet()
                {
                    Code = mapno,
                    Geometry = GeometryHelper.ExtentToPolygon(xmin + (Width / ColLength * (colindex - 1)),
                        ymin + (Height / RowLength * (RowLength - rowindex)),
                        xmin + (Width / ColLength * (colindex)),
                        ymin + (Height / RowLength * (RowLength - rowindex + 1)))
                };
            }
            else
            {
                if (xmax == xmin) xmax = xmin + Width;
                if (ymax == ymin) ymax = ymin + Height;
                return new Mapsheet()
                {
                    Code = mapno,
                    Geometry = GeometryHelper.ExtentToPolygon(xmin, ymin, xmax, ymin)
                };
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="mapno"></param>
        /// <param name="colindex"></param>
        /// <param name="rowindex"></param>
        /// <param name="colLength"></param>
        /// <param name="rowLength"></param>
        /// <returns></returns>
        private string GetSheetCode(string mapno, int colindex, int rowindex,int colLength, int rowLength)
        {
            if (colLength == 1 && rowLength == 1) return mapno;
            int nm = Math.Abs(colindex + (rowindex - 1) * rowLength);            
            int tmpr = (int)Math.Ceiling(rowindex / 2.0);
            int idx = Math.Abs((int)Math.Ceiling(colindex / 2.0) + (tmpr - 1) * rowLength / 2);
            if (mapno.Contains("["))
            {
                int idx1 = mapno.IndexOf('[');
                int idx2 = mapno.IndexOf(']');
                string a_d = mapno.Substring(idx1 + 1, idx2 - idx1 - 1);
                string[] ads = a_d.Split('|');
                string tmp = "";
                foreach (string s in ads)
                {
                    if (string.IsNullOrWhiteSpace(s)) continue;
                    if (s.Contains("-"))
                    {
                        string[] s1 = s.Split('-');
                        int len = 0;
                        if (VerifyHelper.IsABC(s1[0])) len = Convert.ToChar(s1[1]) - Convert.ToChar(s1[0]);
                        else if (VerifyHelper.IsInteger(s1[0])) len = int.Parse(s1[1]) - int.Parse(s1[0]);
                        if (Math.Abs(len)+1 == rowLength)
                        {
                            if (VerifyHelper.IsABC(s1[0])) tmp += Convert.ToString((char)(Convert.ToChar(s1[0]) + idx - 1)).ToString();
                            else if (VerifyHelper.IsInteger(s1[0])) tmp += Convert.ToString(int.Parse(s1[0]) + idx - 1).ToString();
                        }
                    }
                    else if(s.Contains("d"))
                    {
                        int n1 = (colindex > 2 ? colindex - 2 : colindex);
                        int m1 = (rowindex > 2 ? rowindex - 2 : rowindex);
                        int nm1 = Math.Abs(n1 + (m1 - 1) * 2);
                        tmp += nm1.ToString();
                    }
                }
                mapno = mapno.Replace(string.Format("[{0}]", a_d), tmp);
            }
            string dd = GetMatchString(mapno, "d");
            if (!string.IsNullOrEmpty(dd) && !string.IsNullOrWhiteSpace(dd))
            {
                if (dd.Length > 1) mapno = mapno.Replace(dd, nm.ToString().PadLeft(dd.Length, '0'));
                else mapno = mapno.Replace(dd, nm.ToString());
            }
            return mapno;
        }

        /// <summary>
        /// 计算图幅分幅格式：4X4；2X2；1X1
        /// </summary>
        /// <param name="scale">比例尺</param>
        /// <param name="xlen">x方向分幅数</param>
        /// <param name="ylen">y方向分幅数</param>
        private void MathItemSize(SheetScale scale,out int xlen, out int ylen)
        {
            xlen = 1;
            ylen = 1;
            if (scale.ParentValue < 10)
                return ;
            SheetScale sp = SheetScale.Create(scale.ParentValue);
            if (sp.Index < 0)
                return ;
            sp.XOffset = scale.XOffset;
            sp.YOffset = scale.YOffset;
            xlen = scale.ParentValue / scale.Value;
            ylen = xlen;
        }
        
        /// <summary>
        /// 根据图号获取其四周8个方向的图幅与自身所在的图幅，按从上到下，从左到右排列
        /// </summary>
        /// <param name="sheetcode">图号</param>
        /// <param name="scale">比例尺</param>
        /// <returns></returns>
        public List<Mapsheet> GetMapSheets(string sheetcode, SheetScale scale)
        {
            if (base.IsGBCode(sheetcode)) return GetMapSheets(sheetcode);
            if (scale == null) throw new Exception("要创建图幅的比例尺不能为空");                
            if (scale.Index < 0)
                throw new Exception("不存在" + scale.Value.ToString() + "的常规比例尺，请改用常规的比例尺！");
            SetSize(scale);
            Mapsheet tf = MathMapSheet(sheetcode, scale);
            if (tf == null) return null;
            int xlen = 1;
            int ylen = 1;
            MathItemSize(scale, out xlen, out ylen);
            double newx = tf.Geometry.Envelope.LowerLeft.X;
            double newy = tf.Geometry.Envelope.LowerLeft.Y;
            List<Mapsheet> tfs = new List<Mapsheet>();
            tfs.Add(MathMapSheet(newx - Width / xlen, newy + Height / ylen, scale));
            tfs.Add(MathMapSheet(newx, newy + Height / ylen, scale));
            tfs.Add(MathMapSheet(newx + Width / xlen, newy + Height / ylen, scale));

            tfs.Add(MathMapSheet(newx - Width / xlen, newy, scale));
            tfs.Add(tf);
            tfs.Add(MathMapSheet(newx + Width / xlen, newy, scale));

            tfs.Add(MathMapSheet(newx - Width / xlen, newy - Height / ylen, scale));
            tfs.Add(MathMapSheet(newx, newy - Height / ylen, scale));
            tfs.Add(MathMapSheet(newx + Width / xlen, newy - Height / ylen, scale));
            return tfs;
        }

        /// <summary>
        /// 根据坐标点获取其四周8个方向的图幅与自身所在的图幅，按从上到下，从左到右排列
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="scale">比例尺</param>
        /// <returns></returns>
        public List<Mapsheet> GetMapSheets(double x, double y, SheetScale scale)
        {
            if (scale == null)
                throw new Exception("要创建图幅的比例尺不能为空");
            if (scale.Index < 0)
                throw new Exception("不存在" + scale.Value.ToString() + "的常规比例尺，请改用常规的比例尺！");
            
            SetSize(scale);
            if (string.IsNullOrEmpty(scale.Format) || string.IsNullOrWhiteSpace(scale.Format))
            {
                return base.GetBaseSheets(x, y, scale);
            }
            else
            {
                Mapsheet tf = MathMapSheet(x, y, scale);
                if (tf == null) return null;
                int xlen = 1;
                int ylen = 1;
                MathItemSize(scale, out xlen, out ylen);
                double newx = tf.Geometry.Envelope.LowerLeft.X;
                double newy = tf.Geometry.Envelope.LowerLeft.Y;
                List<Mapsheet> tfs = new List<Mapsheet>();
                tfs.Add(MathMapSheet(newx - Width / xlen, newy + Height / ylen, scale));
                tfs.Add(MathMapSheet(newx, newy + Height / ylen, scale));
                tfs.Add(MathMapSheet(newx + Width / xlen, newy + Height / ylen, scale));

                tfs.Add(MathMapSheet(newx - Width / xlen, newy, scale));
                tfs.Add(tf);
                tfs.Add(MathMapSheet(newx + Width / xlen, newy, scale));

                tfs.Add(MathMapSheet(newx - Width / xlen, newy - Height / ylen, scale));
                tfs.Add(MathMapSheet(newx, newy - Height / ylen, scale));
                tfs.Add(MathMapSheet(newx + Width / xlen, newy - Height / ylen, scale));
                return tfs;
            }
        }

        /// <summary>
        /// 获取空间对象所在的图幅集合对象
        /// </summary>
        /// <param name="geometry">空间范围</param>
        /// <param name="scale">对应的比例尺</param>
        /// <param name="removespace">是否移除与空间对象不想交的空白图幅。默认为true：移除</param>
        /// <returns></returns>
        public List<Mapsheet> GetMapSheets(IGeometry geometry, SheetScale scale, bool removespace = true)
        {
            if (geometry == null) throw new Exception("要创建图幅的空间对象不能为空");
            if (scale == null) throw new Exception("要创建图幅的比例尺不能为空");
            if (scale.Index < 0) throw new Exception("不存在" + scale.Value.ToString() + "的常规比例尺，请改用常规的比例尺！"); 
            SetSize(scale);
            base.SetFullExtent(geometry.Envelope);
            if (string.IsNullOrEmpty(scale.Format) || string.IsNullOrWhiteSpace(scale.Format))
                return base.GetBaseSheets(geometry, scale, removespace);
            else
            {
                IRelationalOperator relOp = geometry as IRelationalOperator;   
                List<Mapsheet> lst = new List<Mapsheet>();
                for (double x = XMin; x < XMax; x += Width)
                {
                    for (double y = YMin; y < YMax; y += Height)
                    {
                        string mapno = GetFormatCode(x, y, scale.Format, scale.XOffset, scale.YOffset);
                        double temy = y;
                        for (int m = RowLength; m > 0; m--)
                        {
                            double tmpx = x;
                            for (int n = 1; n <= ColLength; n++)
                            {
                                string tmpno = GetSheetCode(mapno, n, m, ColLength, RowLength);
                                IPolygon polygon = GeometryHelper.ExtentToPolygon(tmpx, temy, tmpx + Width / ColLength, temy + Height / RowLength);
                                tmpx += Width / ColLength;
                                if (scale.ParentValue > 0)
                                    if (relOp.Disjoint(polygon))
                                        continue;
                                lst.Add(new Mapsheet()
                                {
                                    Code = tmpno,
                                    Geometry = polygon
                                });
                            }
                            temy += Height / RowLength;
                        }
                    }
                }
                return lst;
            }
        }
        
        /// <summary>
        /// 获取空间对象所在的图幅集合对象
        /// </summary>
        /// <param name="geometrys">空间范围</param>
        /// <param name="scale">对应的比例尺</param>
        /// <param name="removespace">是否移除与空间对象不想交的空白图幅。默认为true：移除</param>
        /// <returns></returns>
        public List<Mapsheet> GetMapSheets(List<IGeometry> geometrys, SheetScale scale, bool removespace = true)
        {
            if (geometrys == null || geometrys.Count == 0) return null;                
            List<Mapsheet> tfs = new List<Mapsheet>();
            foreach (IGeometry geo in geometrys)
            {
                if (geo == null || geo.IsEmpty) continue;                    
                List<Mapsheet> tmptfs = GetMapSheets(geo, scale, true);
                if (tmptfs == null || tmptfs.Count == 0) continue;                    
                tfs = tfs.Union(tmptfs, new MapsheetListEquality()).ToList();
            }
            return tfs;
        }
        
        /// <summary>
        /// 检查图号是否正确，且与比例尺是否一致
        /// </summary>
        /// <param name="sheetcode"></param>
        /// <param name="scale"></param>
        /// <returns></returns>
        public bool CheckCodeAndScale(string sheetcode, SheetScale scale)
        {
            if (scale.Index < 0)
                return false;
            SheetScale st = GetScaleByCode(sheetcode);
            if (st == null || st.Index < 0)
            {
                if (scale.Value > 2000)
                    return false;
                double x = 0;
                double y = 0;
                return CheckFormatCode(sheetcode, scale.Format, out x, out y, scale.XOffset, scale.YOffset);
            }
            else
            {
                return st.Value == scale.Value;
            }
        }

    }
}
